﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using ADONETDataServicesExtension.Utils;
using System.Reflection;
using ADONETDataServicesExtension.Providers;
using System.Data.Objects.DataClasses;
using ADONETDataServicesExtension.BLLUtils;
using System.Collections;

namespace ADONETDataServicesExtension.Parsing
{
    public class ExpressionParser : FrameworkEncapsulatedType<object>
    {
        internal const string FrameworkTypeName = "System.Data.Services.Parsing.RequestQueryParser+ExpressionParser";

        private static readonly ConstantExpression _falseLiteral;
        private RequestDescription _description;

        static ExpressionParser()
        {
            _falseLiteral = ReflectionHelper.GetStaticField<ConstantExpression>(FrameworkTypeName, "falseLiteral");
        }
        public ExpressionParser(IDataService service, ParameterExpression parameterForIt, string expression, RequestDescription description)
        {
            FrameworkObject = ReflectionHelper.CreateInstance(FrameworkTypeName, service.FrameworkObject, parameterForIt, expression);
            _description = description;
        }

        public Expression ParseWhere(out DoneTier dt)
        {
            int position = Lexer.Position;
            Expression falseLiteral = ParseExpression(out dt);
            if (falseLiteral == null)
                return null;
            if (RequestQueryParser.IsNullConstant(falseLiteral))
                falseLiteral = _falseLiteral;
            else if (falseLiteral.Type == typeof(bool?))
                falseLiteral = Expression.Condition(Expression.Equal(falseLiteral, Expression.Constant(null, typeof(bool?))), _falseLiteral, Expression.Property(falseLiteral, "Value"));
            else if (falseLiteral.Type != typeof(bool))
                throw ParseError(Strings.RequestQueryParser_ExpressionTypeMismatch(GetTypeName(typeof(bool)), position));
            if (dt == DoneTier.DoneInDB)
                Lexer.ValidateToken(TokenId.End);
            return falseLiteral;
        }

        private ExpressionLexer Lexer
        {
            get
            {
                return ReflectionHelper.Convert(ReflectionHelper.GetField(FrameworkTypeName, "lexer", FrameworkObject), frameworkValue => new ExpressionLexer(frameworkValue));
            }
        }

        private Expression ParseExpression(out DoneTier dt)
        {
            RecurseEnter();
            Expression expression = ParseLogicalOr(out dt);
            RecurseLeave();
            return expression;
        }

        private Expression ReturnNullWithRecurseLeave()
        {
            RecurseLeave();
            return null;
        }

        private string GetTypeName(Type type)
        {
            return ReflectionHelper.InvokeMethod<string>(FrameworkTypeName, "GetTypeName", FrameworkObject, type);
        }

        private static Exception ParseError(string message)
        {
            return ReflectionHelper.InvokeStaticMethod<Exception>(FrameworkTypeName, "ParseError", message);
        }

        private void RecurseEnter()
        {
            ReflectionHelper.InvokeVoidMethod(FrameworkTypeName, "RecurseEnter", FrameworkObject);
        }

        private Expression ParseLogicalOr(out DoneTier dt)
        {
            RecurseEnter();
            Expression left = ParseLogicalAnd(out dt);
            if (left == null)
                return ReturnNullWithRecurseLeave();
            if (TokenIdentifierIs("or"))
            {
                if (dt != DoneTier.DoneInDB)
                {
                    dt = DoneTier.DoneInServer;
                    return ReturnNullWithRecurseLeave();
                }
                do
                {
                    Token currentToken = CurrentToken;
                    Lexer.NextToken();
                    DoneTier dtTmp;
                    Expression right = ParseLogicalAnd(out dtTmp);
                    if (dtTmp != DoneTier.DoneInDB)
                    {
                        dt = DoneTier.DoneInServer;
                        return ReturnNullWithRecurseLeave();
                    }
                    CheckAndPromoteOperands(ReflectionHelper.GetFrameworkType("System.Data.Services.Parsing.OperationSignatures+ILogicalSignatures"), currentToken.Text, ref left, ref right, currentToken.Position);
                    left = Expression.OrElse(left, right);
                } while (TokenIdentifierIs("or"));
            }
            RecurseLeave();
            return left;
        }

        private Expression ParseLogicalAnd(out DoneTier dt)
        {
            RecurseEnter();
            Expression left = ParseComparison();
            if (left != null)
                dt = DoneTier.DoneInDB;
            else
            {
                LexerNextTokenWhile("and");
                dt = DoneTier.DoneInServer;
            }
            while (TokenIdentifierIs("and"))
            {
                Token currentToken = CurrentToken;
                Lexer.NextToken();
                Expression right = ParseComparison();
                if (right != null)
                {
                    if (left != null)
                    {
                        CheckAndPromoteOperands(ReflectionHelper.GetFrameworkType("System.Data.Services.Parsing.OperationSignatures+ILogicalSignatures"), currentToken.Text, ref left, ref right, currentToken.Position);
                        left = Expression.AndAlso(left, right);
                    }
                    else
                        left = right;
                    dt = dt | DoneTier.DoneInDB;
                }
                else
                {
                    dt = dt | DoneTier.DoneInServer;
                    LexerNextTokenWhile("and");
                }
            }
            RecurseLeave();
            return left;
        }

        private void LexerNextTokenWhile(string tokenLookedFor)
        {
            while (!(TokenIdentifierIs(tokenLookedFor) || Lexer.CurrentToken.Id == TokenId.CloseParen || Lexer.CurrentToken.Id == TokenId.End))
                Lexer.NextToken();
        }

        private void RecurseLeave()
        {
            ReflectionHelper.InvokeVoidMethod(FrameworkTypeName, "RecurseLeave", FrameworkObject);
        }

        private bool TokenIdentifierIs(string id)
        {
            return ReflectionHelper.InvokeMethod<bool>(FrameworkTypeName, "TokenIdentifierIs", FrameworkObject, id);
        }

        private Token CurrentToken
        {
            get
            {
                return ReflectionHelper.Convert(ReflectionHelper.GetProperty(FrameworkTypeName, "CurrentToken", FrameworkObject), frameworkValue => new Token(frameworkValue));
            }
            set
            {
                ReflectionHelper.SetProperty(FrameworkTypeName, "CurrentToken", FrameworkObject, value == null ? null : value.FrameworkObject);
            }
        }

        private void CheckAndPromoteOperands(Type signatures, string operationName, ref Expression left, ref Expression right, int errorPos)
        {
            ReflectionHelper.InvokeVoidMethod(FrameworkTypeName, "CheckAndPromoteOperands", FrameworkObject, signatures, operationName, left, right, errorPos);
        }

        private Expression ParseComparison()
        {
            RecurseEnter();
            Expression expression = ParseAdditive();
            if (expression == null)
                return ReturnNullWithRecurseLeave();
            while (CurrentToken.IsComparisonOperator)
            {
                Token currentToken = CurrentToken;
                Lexer.NextToken();
                Expression expression2 = ParseAdditive();
                if (expression2 == null)
                    return ReturnNullWithRecurseLeave();
                bool isEqualityOperator = currentToken.IsEqualityOperator;
                if ((isEqualityOperator && !expression.Type.IsValueType) && !expression2.Type.IsValueType)
                {
                    if (expression.Type != expression2.Type)
                    {
                        if (!RequestQueryParser.IsNullConstant(expression))
                        {
                            if (!RequestQueryParser.IsNullConstant(expression2))
                            {
                                if (!expression.Type.IsAssignableFrom(expression2.Type))
                                {
                                    if (!expression2.Type.IsAssignableFrom(expression.Type))
                                        throw IncompatibleOperandsError(currentToken.Text, expression, expression2, currentToken.Position);
                                    expression = Expression.Convert(expression, expression2.Type);
                                }
                                else
                                    expression2 = Expression.Convert(expression2, expression.Type);
                            }
                            else
                                expression2 = Expression.Constant(null, expression.Type);
                        }
                        else
                            expression = Expression.Constant(null, expression2.Type);
                    }
                }
                else if ((expression == RequestQueryParser.NullLiteral) || (expression2 == RequestQueryParser.NullLiteral))
                {
                    if (!isEqualityOperator)
                        throw ParseError(Strings.RequestQueryParser_NullOperatorUnsupported(currentToken.Text, currentToken.Position, Lexer.ExpressionText));
                    if (!RequestQueryParser.TypeAllowsNull(expression.Type))
                        expression = Expression.Convert(expression, typeof(Nullable<>).MakeGenericType(new Type[] { expression.Type }));
                    else if (!RequestQueryParser.TypeAllowsNull(expression2.Type))
                        expression2 = Expression.Convert(expression2, typeof(Nullable<>).MakeGenericType(new Type[] { expression2.Type }));
                }
                else
                {
                    Type signatures = isEqualityOperator ? ReflectionHelper.GetFrameworkType("System.Data.Services.Parsing.OperationSignatures+IEqualitySignatures") : ReflectionHelper.GetFrameworkType("System.Data.Services.Parsing.OperationSignatures+IRelationalSignatures");
                    CheckAndPromoteOperands(signatures, currentToken.Text, ref expression, ref expression2, currentToken.Position);
                }
                string text = currentToken.Text;
                if (text != null)
                {
                    switch (text)
                    {
                        case "eq":
                            expression = GenerateEqual(expression, expression2);
                            break;
                        case "ne":
                            expression = GenerateNotEqual(expression, expression2);
                            break;
                        case "gt":
                            expression = GenerateGreaterThan(expression, expression2);
                            break;
                        case "ge":
                            expression = GenerateGreaterThanEqual(expression, expression2);
                            break;
                        case "lt":
                            expression = GenerateLessThan(expression, expression2);
                            break;
                        case "le":
                            expression = GenerateLessThanEqual(expression, expression2);
                            break;
                    }
                }
            }
            RecurseLeave();
            return expression;
        }

        private Expression ParseAdditive()
        {
            RecurseEnter();
            Expression left = ParseMultiplicative();
            if (left == null)
                return ReturnNullWithRecurseLeave();
            while (CurrentToken.IdentifierIs("add") || CurrentToken.IdentifierIs("sub"))
            {
                Token currentToken = CurrentToken;
                Lexer.NextToken();
                Expression right = ParseMultiplicative();
                if (right == null)
                    return ReturnNullWithRecurseLeave();
                if (currentToken.IdentifierIs("add"))
                {
                    CheckAndPromoteOperands(ReflectionHelper.GetFrameworkType("System.Data.Services.Parsing.OperationSignatures+IAddSignatures"), currentToken.Text, ref left, ref right, currentToken.Position);
                    left = GenerateAdd(left, right);
                }
                else
                {
                    CheckAndPromoteOperands(ReflectionHelper.GetFrameworkType("System.Data.Services.Parsing.OperationSignatures+ISubtractSignatures"), currentToken.Text, ref left, ref right, currentToken.Position);
                    left = GenerateSubtract(left, right);
                }
            }
            RecurseLeave();
            return left;
        }

        private static Expression GenerateAdd(Expression left, Expression right)
        {
            return ReflectionHelper.InvokeStaticMethod<Expression>(FrameworkTypeName, "GenerateAdd", left, right);
        }

        private static Expression GenerateSubtract(Expression left, Expression right)
        {
            return ReflectionHelper.InvokeStaticMethod<Expression>(FrameworkTypeName, "GenerateSubtract", left, right);
        }

        private Expression ParseMultiplicative()
        {
            RecurseEnter();
            Expression left = ParseUnary();
            if (left == null)
                return ReturnNullWithRecurseLeave();
            while ((CurrentToken.IdentifierIs("mul") || CurrentToken.IdentifierIs("div")) || CurrentToken.IdentifierIs("mod"))
            {
                Token currentToken = CurrentToken;
                Lexer.NextToken();
                Expression right = ParseUnary();
                if (right == null)
                    return ReturnNullWithRecurseLeave();
                CheckAndPromoteOperands(ReflectionHelper.GetFrameworkType("System.Data.Services.Parsing.OperationSignatures+IArithmeticSignatures"), currentToken.Text, ref left, ref right, currentToken.Position);
                if (currentToken.IdentifierIs("mul"))
                    left = Expression.Multiply(left, right);
                else
                {
                    if (currentToken.IdentifierIs("div"))
                    {
                        left = Expression.Divide(left, right);
                        continue;
                    }
                    left = Expression.Modulo(left, right);
                }
            }
            RecurseLeave();
            return left;
        }

        private Expression ParseUnary()
        {
            RecurseEnter();
            if ((CurrentToken.Id == TokenId.TokenIdMinus) || CurrentToken.IdentifierIs("not"))
            {
                Token currentToken = CurrentToken;
                Lexer.NextToken();
                if ((currentToken.Id == TokenId.TokenIdMinus) && ExpressionLexer.IsNumeric(CurrentToken.Id))
                {
                    Token token2 = CurrentToken;
                    token2.Text = "-" + token2.Text;
                    token2.Position = currentToken.Position;
                    CurrentToken = token2;
                    RecurseLeave();
                    return ParsePrimary();
                }
                Expression expr = ParseUnary();
                if (expr == null)
                    return null;
                if (currentToken.Id == TokenId.TokenIdMinus)
                {
                    CheckAndPromoteOperand(ReflectionHelper.GetFrameworkType("System.Data.Services.Parsing.OperationSignatures+INegationSignatures"), currentToken.Text, ref expr, currentToken.Position);
                    expr = Expression.Negate(expr);
                }
                else
                {
                    CheckAndPromoteOperand(ReflectionHelper.GetFrameworkType("System.Data.Services.Parsing.OperationSignatures+INotSignatures"), currentToken.Text, ref expr, currentToken.Position);
                    if ((expr.Type != typeof(bool)) && (expr.Type != typeof(bool?)))
                    {
                        throw ParseError(Strings.RequestQueryParser_NotDoesNotSupportType(expr.Type));
                    }
                    expr = Expression.Not(expr);
                }
                RecurseLeave();
                return expr;
            }
            RecurseLeave();
            return ParsePrimary();
        }

        private void CheckAndPromoteOperand(Type signatures, string operationName, ref Expression expr, int errorPos)
        {
            var parameters = new object[] { signatures, operationName, expr, errorPos };
            ReflectionHelper.InvokeVoidMethod(FrameworkTypeName, "CheckAndPromoteOperand", FrameworkObject, parameters);
            expr = (Expression)parameters[2];
        }

        private Expression ParsePrimary()
        {
            RecurseEnter();
            Type bllType = _description.TargetElementType;
            Expression instance = ParsePrimaryStart(ref bllType);
            if (instance == null)
                return ReturnNullWithRecurseLeave();
            while (CurrentToken.Id == TokenId.Slash)
            {
                Lexer.NextToken();
                instance = ParseMemberAccess(instance, bllType);
            }
            RecurseLeave();
            return instance;
        }

        private Expression ParseTypedLiteral(Type targetType, string targetTypeName)
        {
            return ReflectionHelper.InvokeMethod<Expression>(FrameworkTypeName, "ParseTypedLiteral", FrameworkObject, targetType, targetTypeName);
        }

        private Expression ParsePrimaryStart(ref Type bllType)
        {
            if (CurrentToken.Id == TokenId.Identifier)
                return ParseIdentifier(ref bllType);
            if (CurrentToken.Id == TokenId.NullLiteral)
                return ParseNullLiteral();
            if (CurrentToken.Id == TokenId.BooleanLiteral)
                return ParseTypedLiteral(typeof(bool), "Edm.Boolean");
            if (CurrentToken.Id == TokenId.StringLiteral)
                return ParseTypedLiteral(typeof(string), "Edm.String");
            if (CurrentToken.Id == TokenId.IntegerLiteral)
                return ParseTypedLiteral(typeof(int), "Edm.Int32");
            if (CurrentToken.Id == TokenId.Int64Literal)
                return ParseTypedLiteral(typeof(long), "Edm.Int64");
            if (CurrentToken.Id == TokenId.SingleLiteral)
                return ParseTypedLiteral(typeof(float), "Edm.Single");
            if (CurrentToken.Id == TokenId.DateTimeLiteral)
                return ParseTypedLiteral(typeof(DateTime), "Edm.DateTime");
            if (CurrentToken.Id == TokenId.DecimalLiteral)
                return ParseTypedLiteral(typeof(decimal), "Edm.Decimal");
            if (CurrentToken.Id == TokenId.DoubleLiteral)
                return ParseTypedLiteral(typeof(double), "Edm.Double");
            if (CurrentToken.Id == TokenId.GuidLiteral)
                return ParseTypedLiteral(typeof(Guid), "Edm.Guid");
            if (CurrentToken.Id == TokenId.BinaryLiteral)
                return ParseTypedLiteral(typeof(byte[]), "Edm.Binary");
            if (CurrentToken.Id == TokenId.OpenParen)
                return ParseParenExpression();
            throw ParseError(Strings.RequestQueryParser_ExpressionExpected(CurrentToken.Position));
        }

        private Expression ParseNullLiteral()
        {
            return ReflectionHelper.InvokeMethod<Expression>(FrameworkTypeName, "ParseNullLiteral", FrameworkObject);
        }

        private Expression ParseParenExpression()
        {
            if (this.CurrentToken.Id != TokenId.OpenParen)
                throw ParseError(Strings.RequestQueryParser_OpenParenExpected(this.CurrentToken.Position));
            Lexer.NextToken();
            DoneTier dt;
            Expression expression = ParseExpression(out dt);
            if (this.CurrentToken.Id != TokenId.CloseParen)
                throw ParseError(Strings.RequestQueryParser_CloseParenOrOperatorExpected(this.CurrentToken.Position));
            Lexer.NextToken();
            return expression;
        }

        private Expression ParseIdentifier(ref Type bllType)
        {
            ValidateToken(TokenId.Identifier);
            if (Lexer.PeekNextToken().Id == TokenId.OpenParen)
                return ParseIdentifierAsFunction();
            return ParseMemberAccess(It, ref bllType);
        }

        private ParameterExpression It
        {
            get
            {
                return ReflectionHelper.GetField<ParameterExpression>(FrameworkTypeName, "it", FrameworkObject);
            }
        }

        private Expression ParseIdentifierAsFunction()
        {
            return ReflectionHelper.InvokeMethod<Expression>(FrameworkTypeName, "ParseIdentifierAsFunction", FrameworkObject);
        }

        private void ValidateToken(int t)
        {
            ReflectionHelper.InvokeVoidMethod(FrameworkTypeName, "ValidateToken", FrameworkObject, t);
        }

        private Expression ParseMemberAccess(Expression instance, Type bllType)
        {
            Type t = bllType;
            return ParseMemberAccess(instance, ref t);
        }
        private Expression ParseMemberAccess(Expression instance, ref Type bllType)
        {
            int position = Lexer.Position;
            string identifier = CurrentToken.GetIdentifier();
            Lexer.NextToken();
            ResourceProperty property = FindProperty(bllType, identifier);
            PropertyInfo propertyInfo;
            if (property == null)
            {
                if (typeof(IEnumerable).IsAssignableFrom(bllType))
                    propertyInfo = bllType.GetProperty(identifier);
                else
                    throw ParseError(Strings.RequestQueryParser_UnknownProperty(identifier, GetTypeName(bllType), position));
            }
            else
                propertyInfo = property.PropertyInfo;
            if (instance.Type != bllType)
            {
                if (property == null)
                    propertyInfo = instance.Type.GetProperty(identifier);
                else if (propertyInfo.DeclaringType.IsAssignableFrom(bllType))
                {
                    var efEntityPropertyAttribute = property.PropertyInfo.Attribute<EFEntityPropertyAttribute>();
                    if (efEntityPropertyAttribute == null)
                        return null;
                    else
                    {
                        string efPropertyName = efEntityPropertyAttribute.EFPropertyName ?? property.Name;
                        property.PropertyInfo = instance.Type.GetProperty(efPropertyName);
                    }
                }
            }
            else
                property.PropertyInfo = ReflectionHelper.GetInstancePropertyInfo(bllType, property.Name);
            if (property != null)
                propertyInfo = property.PropertyInfo;
            Expression expression = Expression.Property(instance, propertyInfo);
            if (property != null)
            {
                if (!(typeof(ComplexObject).IsAssignableFrom(propertyInfo.PropertyType) || typeof(ComplexObject).IsAssignableFrom(instance.Type)))
                    expression = ConsiderNullPropagation(instance, expression);
                if (property.ResourceContainer != null)
                {
                    Expression expression2 = DataServiceConfiguration.ComposeQueryInterceptors(Service, property.ResourceContainer);
                    if (expression2 != null)
                        expression = RequestQueryProcessor.ComposePropertyNavigation(expression, (LambdaExpression)expression2, Provider.NullPropagationRequired);
                }
            }
            bllType = bllType.GetProperty(propertyInfo.Name).PropertyType;
            return expression;
        }

        public IDataService Service
        {
            get
            {
                return ReflectionHelper.Convert(ReflectionHelper.GetField(FrameworkTypeName, "service", FrameworkObject), frameworkValue => new IDataService(frameworkValue));
            }
        }

        public IDataServiceProvider Provider
        {
            get
            {
                return ReflectionHelper.Convert(ReflectionHelper.GetField(FrameworkTypeName, "provider", FrameworkObject), frameworkValue => new IDataServiceProvider(frameworkValue));
            }
        }

        private Expression ConsiderNullPropagation(Expression element, Expression notNullExpression)
        {
            return ReflectionHelper.InvokeMethod<Expression>(FrameworkTypeName, "ConsiderNullPropagation", FrameworkObject, element, notNullExpression);
        }

        private ResourceProperty FindProperty(Type type, string memberName)
        {
            ResourceProperty property = Provider.TryResolvePropertyName(type, memberName);
            if (property == null)
            {
                return null;
            }
            if (property.ResourceContainer != null)
            {
                Service.Configuration.CheckResourceRightsForRead(property.ResourceContainer, true);
            }
            return property;
        }

        private Exception IncompatibleOperandsError(string operationName, Expression left, Expression right, int pos)
        {
            return ReflectionHelper.InvokeMethod<Exception>(FrameworkTypeName, "IncompatibleOperandsError", FrameworkObject, left, right, pos);
        }

        private static Expression GenerateEqual(Expression left, Expression right)
        {
            if (left.Type == typeof(byte[]))
            {
                MethodInfo method = ReflectionHelper.GetFrameworkType("System.Data.Services.Parsing.RequestQueryParser+ExpressionParser").GetMethod("ByteArraysEqual", BindingFlags.NonPublic | BindingFlags.Static);
                return Expression.Equal(left, right, false, method);
            }
            return Expression.Equal(left, right);
        }

        private static Expression GenerateGreaterThan(Expression left, Expression right)
        {
            if (left.Type == typeof(string))
            {
                return Expression.GreaterThan(left, right, false, GetStringCompareMethod("StringGreaterThanMethod"));
            }
            return Expression.GreaterThan(left, right);
        }

        private static Expression GenerateGreaterThanEqual(Expression left, Expression right)
        {
            if (left.Type == typeof(string))
            {
                return Expression.GreaterThanOrEqual(left, right, false, GetStringCompareMethod("StringGreaterThanOrEqualMethod"));
            }
            return Expression.GreaterThanOrEqual(left, right);
        }

        private static Expression GenerateLessThan(Expression left, Expression right)
        {
            if (left.Type == typeof(string))
            {
                return Expression.LessThan(left, right, false, GetStringCompareMethod("StringLessThanMethod"));
            }
            return Expression.LessThan(left, right);
        }

        private static Expression GenerateLessThanEqual(Expression left, Expression right)
        {
            if (left.Type == typeof(string))
            {
                return Expression.LessThanOrEqual(left, right, false, GetStringCompareMethod("StringLessThanOrEqualMethod"));
            }
            return Expression.LessThanOrEqual(left, right);
        }

        private static Expression GenerateNotEqual(Expression left, Expression right)
        {
            if (left.Type == typeof(byte[]))
            {
                MethodInfo method = ReflectionHelper.GetFrameworkType("System.Data.Services.Parsing.RequestQueryParser+ExpressionParser").GetMethod("ByteArraysNotEqual", BindingFlags.NonPublic | BindingFlags.Static);
                return Expression.NotEqual(left, right, false, method);
            }
            return Expression.NotEqual(left, right);
        }

        private static MethodInfo GetStringCompareMethod(string methodName)
        {
            return ReflectionHelper.InvokeStaticMethod<MethodInfo>(FrameworkTypeName, "GetStringCompareMethod", methodName);
        }

        public IEnumerable<DynamicOrdering> ParseOrdering(out DoneTier dt)
        {
            Expression expression;
            var list = new List<DynamicOrdering>();
            dt = 0;
            while (true)
            {
                DoneTier dtTmp;
                expression = ParseExpression(out dtTmp);
                dt = dt | dtTmp;
                bool ascending = true;
                if (TokenIdentifierIs("asc"))
                    Lexer.NextToken();
                else if (TokenIdentifierIs("desc"))
                {
                    Lexer.NextToken();
                    ascending = false;
                }
                list.Add(new DynamicOrdering(expression, ascending));
                if (CurrentToken.Id == TokenId.Comma)
                    Lexer.NextToken();
                else
                    break;
            }
            ValidateToken(TokenId.End);
            return list;
        }
    }
}
